package agent;

import common.DominoState;
import java.util.LinkedList;
import common.Piece;
import common.Side;
import common.Move;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

/**
 * Represents what the agent knows about the current state of the game and, maybe, about the game history.
 * Sugestions:
 * - We sugest the implementation of a method that returns the list of pieces
 *   that the opponent may have: 
 *   Set of all domino pieces - Already played pieces - Current agent pieces - Maybe something else.
 * - Important: implement a method that returns an AgentSearchState version of
 *   the current game state (this state).
 * - Other aspects you may consider necessary.
 */
public class AgentCurrentState extends AgentState {

    private int numberOfOpponentPieces = DominoState.PIECES_PER_PLAYER;
    
    
    public AgentCurrentState(LinkedList<Piece> agentPieces) {
        super(agentPieces, null);
    }

    /**
     * Places a piece of the given player in the given side of the list of
     * already placed pieces. It should be used to update the current state as
     * known by the agent (see atribute currentState in class Agent). It is not
     * meant to be used to place pieces during the search process (at least in
     * is present version). We advise students to implement a different method
     * in class AgentSearchState.
     *
     * @param player the player that places the piece.
     * @param side the side of the list of already played pieces where the piece must be placed.
     * @param piece the piece to be placed.
     * @return true if the piece can be placed (valid move) and false, otherwise.
     */    
    public boolean placePiece(Player player, Side side, Piece piece) {
        if (super.placePiece(side, piece)) {
            if (player == Player.AGENT) {
                agentPieces.remove(piece);
            } else {
                numberOfOpponentPieces--;
                opponentPossiblePieces.remove(piece);
            }
            lastPlayer = player;
            return true;
        }
        return false;
    }

    //Used by the random algorithm
    public LinkedList<Move> getAgentPossibleMoves() {
        LinkedList<Move> possibleMoves = new LinkedList<>();
        for (Piece piece : agentPieces) {
            if (isValidMove(Side.LEFT, piece)) {
                Move m = new Move(Side.LEFT, piece);
                possibleMoves.add(m);
            }
            if (isValidMove(Side.RIGHT, piece)) {
                Move m = new Move(Side.RIGHT, piece);
                possibleMoves.add(m);
            }
        }
        return possibleMoves;
    }
  
    public int getNumberOfOpponentPieces() {
        return numberOfOpponentPieces;
    }
    
    //criar metodo getOpponentPossiblePices
    public LinkedList<Piece> getOpponentPossiblePieces() {
        return opponentPossiblePieces;
    }
    
    
    public LinkedList<AgentSearchState> buildGuessedCurrentStates(int handsLimit, Random random) {
        verifyLastPlay();
        LinkedList<AgentSearchState> guessedCurrentStates = new LinkedList<>();
        int numPossibleOpponentHands = Combinations.getNumCombinations(opponentPossiblePieces.size(), numberOfOpponentPieces);
        int numHands = handsLimit < numPossibleOpponentHands ? handsLimit : numPossibleOpponentHands;
        LinkedList<int[]> combinations =
                Combinations.computeCombinations(opponentPossiblePieces.size(), numberOfOpponentPieces);
        Collections.shuffle(combinations, random);

        for (int i = 0; i < numHands; i++) {
            LinkedList<Piece> guessedPieces = new LinkedList<>();
            for (int j = 0; j < numberOfOpponentPieces; j++) {
                guessedPieces.add(opponentPossiblePieces.get(combinations.get(i)[j]));
            }
            guessedCurrentStates.add(getAgentSearchState(guessedPieces));
        }

        return guessedCurrentStates;
    }
	
    private AgentSearchState getAgentSearchState(LinkedList<Piece> opponentPieces) {
        return new AgentSearchState(
                (LinkedList<Piece>) playedPieces.clone(),
                (LinkedList<Piece>) agentPieces.clone(),
                (LinkedList<Piece>) opponentPieces.clone(),
                leftValue, rightValue, Player.AGENT, lastPlayer);
    }
    
    protected void verifyLastPlay(){
        if(lastPlayer == Player.AGENT)
            this.recalcOpponentPossiblePiecesBasedOnPlayerSkip(leftValue, rightValue);
    }
}
